/**  
 * <p>Title: ClassUtils.java</p>  
 * <p>Description: Class类加载工具</p>  
 * <p>Copyright: Copyright (c) 2018</p>    
 * @author ji'anyuan  
 * @date 2018年3月10日  
 * @version 1.0  
 */
package org.mango.jiayin.operater.utils;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * <p>
 * Title: ClassUtils
 * </p>
 * <p>
 * Description: Class类加载工具
 * </p>
 * 
 * @author ji'anyuan
 * @date 2018年3月10日
 */
public class ClassUtils {

	private static final Logger logger = LoggerFactory
			.getLogger(ClassUtils.class);

	/**
	 * 
	 * <p>
	 * Title: scanClassesWithInterface
	 * </p>
	 * <p>
	 * Description: 根据包名获取该包下指定接口的子类
	 * </p>
	 * 
	 * @param interClass
	 * @param packageName
	 * @return
	 */
	public static List<Class<?>> scanClassesWithInterface(Class<?> interClass,
			String packageName) {
		List<Class<?>> classList = new ArrayList<Class<?>>();
		if (interClass.isInterface()) {
			for (Class<?> cls : scanClasses(packageName)) {
				if (interClass.isAssignableFrom(cls) && !interClass.equals(cls)) {
					classList.add(cls);
				}
			}
		}
		return classList;
	}

	/**
	 * 
	 * <p>
	 * Title: scanClasses
	 * </p>
	 * <p>
	 * Description: 根据包路径扫描所以的类
	 * </p>
	 * 
	 * @param packageName
	 *            例如:org.mango.jiayin.operater
	 * @return
	 */
	public static List<Class<?>> scanClasses(String packageName) {
		List<Class<?>> classList = new ArrayList<Class<?>>();

		String path = packageName.replace('.', '/');

		try {
			Enumeration<URL> urls = Thread.currentThread()
					.getContextClassLoader().getResources(path);

			while (urls.hasMoreElements()) {
				URL url = urls.nextElement();
				if ("file".equals(url.getProtocol())) {
					scanClassesByfile(packageName,
							URLDecoder.decode(url.getFile(), "utf-8"),
							classList);
				}
			}
		} catch (IOException e) {
			logger.error("failed to scanClasses:{}", new Object[] {
					packageName, e });
		}

		return classList;
	}

	/**
	 * <p>
	 * Title: scanClassesByfile
	 * </p>
	 * <p>
	 * Description: 根据文件扫描加载类
	 * </p>
	 * 
	 * @param packageName
	 * @param decode
	 * @param classList
	 */
	private static void scanClassesByfile(String packageName, String filePath,
			List<Class<?>> classList) {
		File dir = new File(filePath);

		if (!dir.exists() || !dir.isDirectory()) {
			return;
		}
		File[] files = dir.listFiles(file -> (file.isDirectory() || file
				.getName().endsWith(".class")));

		if (files == null || files.length == 0) {
			logger.error("path {} is empty", filePath);
		}

		for (File file : files) {
			if (file.isDirectory()) {
				scanClassesByfile(packageName + "." + file.getName(),
						file.getAbsolutePath(), classList);
			} else {
				try {
					String className = packageName
							+ "."
							+ file.getName()
									.substring(
											0,
											file.getName().length()
													- ".class".length());
					Class<?> cls = Thread.currentThread()
							.getContextClassLoader().loadClass(className);
					classList.add(cls);
				} catch (ClassNotFoundException e) {
					logger.error("can not found class:{}",
							new Object[] { file.getName(), e });
				}
			}
		}

	}
}
